package dbmanager

import (
	"reflect"
	"github.com/astaxie/beego/orm"
	"fmt"
	"strings"
	"regexp"
	"strconv"
	"cloud_worm/util/umodels/mysqldb"
)

const (
	PackageWormAgent = "worm_agent"
	PackageWormSrv = "worm_srv"
	PackagePre = "worm"

	PlatLinux = "Linux"
	PlatDarwin = "Darwin"
)

type Package struct {
	Id 			int64
	Name 		string
	FileName 	string
	UploadUser 	string
	Version 	int
	Platform 	string
	Md5 		string
	Url 		string
	Created 	int64
	Updated		int64
	Status 		int
}

func (w *Package) TableName() string {
	return reflect.TypeOf(*w).Name()
}

func (w *Package) Read(fields ...string) error {
	err := orm.NewOrm().Read(w, fields...)
	if err != nil {
		// todo: 具体错误处理，参考(https://beego.me/docs/mvc/model/object.md)
		// orm.ErrNoRows
		return fmt.Errorf("%s, %s", w.TableName(), err.Error())
	}
	return nil
}

func (w *Package) Update(fields ...string) error {
	_, err := orm.NewOrm().Update(w, fields...)
	if err != nil {
		return fmt.Errorf("%s, %s", w.TableName(), err.Error())
	}
	return nil
}

func (w *Package) Insert() error {
	_, err := orm.NewOrm().Insert(w)
	if err != nil {
		return fmt.Errorf("%s, %s", w.TableName(), err.Error())
	}
	return nil
}

// init 注册表WolverinePackage
func init()  {
	orm.RegisterModel(new(Package))
}

// Package.ParseFileName 解析文件名，得到包的信息
func (w *Package) ParseFileName(fileName string) error {
	if strings.Contains(fileName, "..") {
		return fmt.Errorf("file contains illegality: %s", fileName)
	}

	// 包文件格式检查
	// 包文件名的格式：{agent}.[0-9]{9|3}.{Darwin}.tar.gz
	var regStr string
	if strings.HasPrefix(fileName, PackagePre) {
		regStr = fmt.Sprintf(`(^%s|^%s)\.([0-9]{9})\.(.+).(tar\.gz)$`, PackageWormAgent, PackageWormSrv)
	} else {
		return fmt.Errorf("file name error:'%s', must has prefix '%s|%s'", fileName, PackageWormAgent, PackageWormSrv)
	}
	reg := regexp.MustCompile(regStr)
	matchs := reg.FindStringSubmatch(fileName)
	if matchs == nil {
		return fmt.Errorf("file name error: '%s', must: {%s|%s}.[0-9]{9|3}.{Darwin}.tar.gz", fileName, PackageWormAgent, PackageWormSrv)
	}

	w.FileName = matchs[0]
	w.Name = matchs[1]
	w.Version, _ = strconv.Atoi(matchs[2])
	w.Platform = matchs[3]

	return nil
}

func (w *Package) SelectMaxVersionPackage(name string, platform string) error {
	qs := orm.NewOrm().QueryTable(w)

	qs.Filter("name", name)
	qs.Filter("platform", platform)

	qs.Filter("status", mysqldb.StatusValid)
	qs.OrderBy("-version")
	qs.Limit(1)

	var result []*Package
	_, err := qs.All(&result)
	if err != nil {
		return err
	}
	if len(result) != 1 {
		return fmt.Errorf("%s select '%s.%s max version error", w.TableName(), name, platform)
	}

	w.Id = result[0].Id
	w.Name = result[0].Name
	w.FileName = result[0].FileName
	w.UploadUser = result[0].UploadUser
	w.Version = result[0].Version
	w.Platform = result[0].Platform
	w.Md5 = result[0].Md5
	w.Url = result[0].Url
	w.Created = result[0].Created
	w.Updated = result[0].Updated
	w.Status = result[0].Status
	return nil
}

func GetPlatform(platform string) string {
	input := strings.ToLower(platform)
	if input == strings.ToLower(PlatLinux) {
		return PlatLinux
	} else if input == strings.ToLower(PlatDarwin) {
		return PlatDarwin
	}
	return ""
}

func (w *Package) Count(name string, fileName string, uploadUser string, version int, md5 string, status int) (int64, error) {
	qs := orm.NewOrm().QueryTable(w)

	if name != mysqldb.SelectStrAll {
		qs = qs.Filter("name__istartswith", name)
	}
	if fileName != mysqldb.SelectStrAll {
		qs = qs.Filter("file_name__istartswith", fileName)
	}
	if uploadUser != mysqldb.SelectStrAll {
		qs = qs.Filter("upload_user__istartswith", uploadUser)
	}
	if version != mysqldb.SelectIntAll {
		qs = qs.Filter("version", version)
	}
	if md5 != mysqldb.SelectStrAll {
		qs = qs.Filter("md5__istartswith", md5)
	}
	if status != mysqldb.SelectIntAll {
		qs = qs.Filter("status", status)
	}

	count, err := qs.Count()
	if err != nil {
		return 0, err
	}
	return count, nil
}

func (w *Package) Select(offset int, limit int, name string, fileName string, uploadUser string,
	version int, md5 string, status int) ([]*Package, error) {

	qs := orm.NewOrm().QueryTable(w).Offset(offset).Limit(limit)

	if name != mysqldb.SelectStrAll {
		qs = qs.Filter("name__istartswith", name)
	}
	if fileName != mysqldb.SelectStrAll {
		qs = qs.Filter("file_name__istartswith", fileName)
	}
	if uploadUser != mysqldb.SelectStrAll {
		qs = qs.Filter("upload_user__istartswith", uploadUser)
	}
	if version != mysqldb.SelectIntAll {
		qs = qs.Filter("version", version)
	}
	if md5 != mysqldb.SelectStrAll {
		qs = qs.Filter("md5__istartswith", md5)
	}
	if status != mysqldb.SelectIntAll {
		qs = qs.Filter("status", status)
	}
	qs.OrderBy("-version")

	var results []*Package
	_, err := qs.All(&results)
	if err != nil {
		return nil, fmt.Errorf("%s, %s", w.TableName(), err.Error())
	}

	return results, nil
}
